"""Common Pydantic utilities."""

from __future__ import annotations

from datetime import datetime
from typing import Any, Generic, TypeVar

from pydantic import BaseModel, ConfigDict, Field, model_validator


# Generic type for paginated responses
T = TypeVar("T")


def to_camel(string: str) -> str:
    """Convert snake_case field names to camelCase for JSON serialization."""
    head, *tail = string.split("_")
    return head + "".join(word.capitalize() for word in tail)


class CamelModel(BaseModel):
    """Base model that serializes field names as camelCase."""

    model_config = ConfigDict(
        populate_by_name=True,
        alias_generator=to_camel,
    )


class ORMBase(CamelModel):
    """Base model with ORM support and camelCase serialization."""

    model_config = ConfigDict(
        populate_by_name=True,
        alias_generator=to_camel,
        from_attributes=True,
    )


class TimestampModel(CamelModel):
    created_at: datetime
    updated_at: datetime


class PaginatedResponse(CamelModel, Generic[T]):
    """Unified paginated response format for all list endpoints.

    Usage:
        ```python
        @router.get("/items", response_model=PaginatedResponse[ItemOut])
        async def get_items(skip: int = 0, limit: int = 20):
            items, total = await service.get_items(skip=skip, limit=limit)
            return PaginatedResponse(
                items=items,
                total=total,
                skip=skip,
                limit=limit,
            )
        ```
    """

    @model_validator(mode="before")
    @classmethod
    def _accept_data_alias(cls, data: Any) -> Any:
        if isinstance(data, dict) and "data" in data and "items" not in data:
            data = dict(data)
            data["items"] = data.pop("data")
        return data

    items: list[T] = Field(description="List of items in current page")
    total: int = Field(ge=0, description="Total number of items across all pages")
    skip: int = Field(ge=0, default=0, description="Number of items skipped")
    limit: int = Field(ge=1, le=100, default=20, description="Maximum items per page")

    @property
    def page(self) -> int:
        """Current page number (1-indexed)."""
        return (self.skip // self.limit) + 1

    @property
    def total_pages(self) -> int:
        """Total number of pages."""
        if self.limit == 0:
            return 0
        return (self.total + self.limit - 1) // self.limit

    @property
    def has_next(self) -> bool:
        """Whether there are more items after current page."""
        return self.skip + self.limit < self.total

    @property
    def has_prev(self) -> bool:
        """Whether there are items before current page."""
        return self.skip > 0
    @property
    def data(self) -> list[T]:
        """Backward compatible alias for items."""
        return self.items
